package me.dqn.noway.model;

import android.content.Context;
import android.util.Log;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import me.dqn.noway.InformationManagerCallback;
import me.dqn.noway.R;
import me.dqn.noway.bean.AddInfoResponse;
import me.dqn.noway.bean.AllResponse;
import me.dqn.noway.bean.DeleteInfoResponse;
import me.dqn.noway.bean.NoWayContext;
import me.dqn.noway.bean.PasswordInformation;
import me.dqn.noway.bean.PasswordUser;
import me.dqn.noway.util.DesEncryptor;
import me.dqn.noway.util.ResponseMapper;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import static android.content.ContentValues.TAG;

/**
 * 用于和服务器的密码信息交互
 */
public class InformationManager {
    OkHttpClient client;
    Context context;
    public InformationManager(Context context) {
        this.context = context;
        this.client = new OkHttpClient().newBuilder()
                //设置超时时间
                .connectTimeout(10, TimeUnit.SECONDS)
                //设置读取超时时间
                .readTimeout(10, TimeUnit.SECONDS)
                //设置写入超时时间
                .writeTimeout(10, TimeUnit.SECONDS)
                .build();
    }
    /**
     * 获取所有的密码信息
     * @param passwordUser 相应的用户
     * @param callback     回调
     */
    public void getAllPasswordInformation(PasswordUser passwordUser, InformationManagerCallback callback) {
        try {
            if (passwordUser == null) {
                throw new NullPointerException();
            }
            FormBody.Builder builder = new FormBody.Builder();
            builder.add(context.getString(R.string.POST_USERNAME), passwordUser.getUsername());
            builder.add(context.getString(R.string.POST_KEY), passwordUser.getDecryptKey());
            Request request = new Request.Builder()
                    .url(context.getString(R.string.GET_ALL_PASSWORD_INFO_URL))
                    .post(builder.build())
                    .build();
            this.client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {

                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    DesEncryptor desEncryptor = DesEncryptor.getIstance();
                    String json = response.body().string();
                    AllResponse allResponse = ResponseMapper.mapToAllResponse(json);
                    if (allResponse.getResult().equals(context.getString(R.string.ACCOUNT_ERROR))) {
                        // 账号错误
                        NoWayContext.getINSTANCE().setPasswordUser(null);
                        callback.onGetInformationFailed("failed to get all information from server.");
                    } else {
                        List<PasswordInformation> temp = new ArrayList<>();
                        for (PasswordInformation passwordInformation : allResponse.getInfo()) {
                            try {
                                // decode data
                                PasswordInformation information = desEncryptor.decryptInformation(NoWayContext.getINSTANCE().getPasswordUser(), passwordInformation);
                                temp.add(information);
                            } catch (Exception e) {
                                e.printStackTrace();
                                callback.onGetInformationFailed(context.getString(R.string.UNKNOW_ERROR));
                            }
                        }
                        allResponse.setInfo(temp);
                        callback.onGetAllInformationDone(allResponse.getInfo());
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            callback.onGetInformationFailed("failed to get all information from server.Exception.");
        }
    }

    /**
     * 添加一组新的密码信息
     *
     * @param passwordUser
     * @param passwordInformation 发送的json结构
     *                            data = {
     *                            'user.username':'dqn',
     *                            'user.decryptKey':'dqndqndq'
     *                            ,
     *                            <p>
     *                            'info.password':'test_password',
     *                            'info.username':'test_username',
     *                            'info.mail':'test_mail邮件',
     *                            'info.type':'test_type',
     *                            'info.detail':'test_detail'
     *                            }
     */
    public void addPasswordInformation(PasswordUser passwordUser, PasswordInformation passwordInformation, InformationManagerCallback callback) {
        DesEncryptor desEncryptor = DesEncryptor.getIstance();
        try {
            if (passwordUser == null) {
                throw new Exception();
            }
            // TODO: 2018/6/9 将user信息加密再发出去
            passwordInformation = desEncryptor.encryptData(NoWayContext.getINSTANCE().getPasswordUser(), passwordInformation);

            FormBody.Builder builder = new FormBody.Builder();
            builder.add("user.username", passwordUser.getUsername());
            builder.add("user.decryptKey", passwordUser.getDecryptKey());

            builder.add("info.password", passwordInformation.getPassword());
            builder.add("info.username", passwordInformation.getUsername());
            builder.add("info.mail", passwordInformation.getMail());
            builder.add("info.type", passwordInformation.getType());
            builder.add("info.detail", passwordInformation.getDetail());

            Request request = new Request.Builder()
                    .url(context.getString(R.string.ADD_PASSWORD_INFO_URL))
                    .post(builder.build())
                    .build();

            this.client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    callback.onAddInformationFailed("error");
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    String json = response.body().string();
                    Log.i(TAG, "onResponse: " + json);
                    AddInfoResponse addInfoResponse = ResponseMapper.mapToAddInfoResponse(json);
                    if (addInfoResponse.getResult().equals("error")) {
                        callback.onAddInformationFailed("add new info failed");
                    } else if (addInfoResponse.getResult().equals("done")) {
                        callback.onAddInformationDone();
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            callback.onAddInformationFailed("error");
        }
    }

    /**
     * delete password information by id
     * # del_url = 'http://localhost:8080/password/info/del'
     * <p>
     * # data_del = {
     * #     'username':'dqn',
     * #     'decryptKey':'dqndqndq',
     * #     'id':'27'
     * # }
     *
     * @param id
     */
    public void deletePasswordInformationById(PasswordUser user, int id, InformationManagerCallback callback) {
        if (user == null) {
            callback.onDeleteInformationFailed("Empty User.");
            return;
        }
        FormBody.Builder builder = new FormBody.Builder();
        builder.add("username", user.getUsername());
        builder.add("decryptKey", user.getDecryptKey());
        builder.add("id", "" + id);

        Request request = new Request.Builder()
                .url(context.getString(R.string.DELETE_INFO_URL))
                .post(builder.build())
                .build();
        this.client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callback.onDeleteInformationFailed(context.getString(R.string.DELETE_FAILED_IO));
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String json = response.body().string();
                if (json == null) {
                    callback.onDeleteInformationFailed(context.getString(R.string.UNKNOW_ERROR));
                } else {
                    DeleteInfoResponse deleteInfoResponse = ResponseMapper.mapTDeleteInfoResponse(json);
                    if ("done".equals(deleteInfoResponse.getResult())) {
                        callback.onDeleteInformationDone();
                    } else {
                        callback.onDeleteInformationFailed(deleteInfoResponse.getInfo());
                    }
                }
            }
        });

    }
}
